import asyncio
import socket
import struct

import select
import time

import cv2
import ffmpeg
import numpy as np
import pyaudio
from PyQt5.QtWidgets import QApplication, QFrame
from PyQt5.QtWidgets import QMainWindow
from PyQt5.QtGui import QResizeEvent, QKeyEvent, QCloseEvent, QPalette, QImage, QMouseEvent, QCursor
import multiprocessing.sharedctypes as mps
from multiprocessing import Process, Event, Queue, Lock
from PyQt5.QtCore import QEvent
from MyLib.UiWidget import *
from MyLib.TestToolApi import Debug
from ctypes import *
from typing import Optional
import sys
import subprocess
import traceback


class StatusData(Structure):
    _fields_ = [('bat', c_float),
                ('t_speed', c_float),
                ('g_speed', c_float),
                ('signal', c_uint8)]


class HeartBeatData(Structure):
    _fields_ = [('delay', c_float),
                ('up', c_float),
                ('down', c_float)]


class MainVideoProcess(Process):

    def __init__(self, logging=True, daemon=True):
        super(MainVideoProcess, self).__init__(daemon=daemon)
        if logging:
            self.__mainDebugQueue = Queue(10)
        else:
            self.__mainDebugQueue = None
        self.__mainDebug = Debug(self.__mainDebugQueue, True, "上位机-客户端模块-主视频流服务")
        self.__MainVideoPauseStatus = Event()
        self.__CloseStatus = Event()
        self.MAIN_VIDEO_STATUS = mps.Value(c_bool, False)
        self.MAIN_VIDEO_DATA = mps.Array(c_char, size_or_initializer=640 * 480 * 3)

    async def __getVideoTask(self):
        self.__mainDebug.info("[主视频流获取器] 已进入该任务")
        self.__MainVideoPauseStatus.set()
        self.MAIN_VIDEO_STATUS.value = False
        while not self.__CloseStatus.is_set():
            try:
                self.__mainDebug.info("[主视频流获取器] 等待任务启动")
                while self.__MainVideoPauseStatus.is_set():
                    if self.__CloseStatus.is_set():
                        break
                    await asyncio.sleep(0)
                if self.__CloseStatus.is_set():
                    break
                else:
                    self.__mainDebug.info("[主视频流获取器] 任务启动成功!")
                    videoStream = await asyncio.subprocess.create_subprocess_shell(
                        "ffmpeg -f flv -i rtmp://139.155.181.21/live/01 -an -f rawvideo -pix_fmt bgr24 -",
                        stdout=asyncio.subprocess.PIPE,
                        stderr=asyncio.subprocess.DEVNULL,
                        shell=True
                    )
                    self.__mainDebug.info("[主视频流获取器] 获取数据中...")
                    while not self.__MainVideoPauseStatus.is_set():
                        if self.__CloseStatus.is_set():
                            break
                        else:
                            rawData = await videoStream.stdout.readexactly(480 * 640 * 3)
                            self.MAIN_VIDEO_STATUS.value = True
                            # self.MAIN_VIDEO_STATUS = False
                            self.MAIN_VIDEO_DATA.raw = rawData
                            # self.MAIN_VIDEO_STATUS = True
                            # print("写入的", self.MAIN_VIDEO_DATA.shape)
                    self.__mainDebug.debug("[主视频流获取器] 任务被暂停!")
                    videoStream.terminate()
            except Exception as e:
                self.__mainDebug.error(
                    f"\n{traceback.format_exc()}\n----------Error----------"
                )
                self.__mainDebug.error("[主视频流获取器] 该任务发生错误, 退出!")
                break
        if self.__CloseStatus.is_set():
            self.__mainDebug.warn("[主视频流获取器] 出现全局错误申请, 退出该任务!")
        self.__CloseStatus.set()
        self.__mainDebug.warn("[主视频流获取器] 任务被中止!")

    def run(self) -> None:
        self.__mainDebug.info("进程启动中...")

        async def main():
            await asyncio.gather(self.__getVideoTask())

        asyncio.run(main())

        self.__mainDebug.debug("进程已结束!")

    def play(self):
        self.__MainVideoPauseStatus.clear()

    def pause(self):
        self.__MainVideoPauseStatus.set()

    def stop(self):
        self.__CloseStatus.set()


class AudioProcess(Process):

    def __init__(self, logging=True, daemon=True):
        super(AudioProcess, self).__init__(daemon=daemon)
        if logging:
            self.__mainDebugQueue = Queue(10)
        else:
            self.__mainDebugQueue = None
        self.__mainDebug = Debug(self.__mainDebugQueue, True, "上位机-客户端模块-音频流进程")
        self.__AudioPauseStatus = Event()
        self.__CloseStatus = Event()

    async def __getAudioTask(self):
        self.__mainDebug.info("[音频流获取器] 已进入该任务")
        self.__AudioPauseStatus.set()
        while not self.__CloseStatus.is_set():
            try:
                self.__mainDebug.info("[音频流获取器] 等待任务启动")
                while self.__AudioPauseStatus.is_set():
                    if self.__CloseStatus.is_set():
                        break
                    await asyncio.sleep(0)
                if self.__CloseStatus.is_set():
                    break
                else:
                    self.__mainDebug.info("[音频流获取器] 任务启动成功!")
                    audioStream = await asyncio.subprocess.create_subprocess_shell(
                        "ffmpeg -f flv -i rtmp://139.155.181.21/live/01 -vn -f wav -",
                        stdout=asyncio.subprocess.PIPE,
                        stderr=asyncio.subprocess.DEVNULL,
                        shell=True
                    )
                    p = pyaudio.PyAudio()
                    stream = p.open(
                        format=pyaudio.paInt16,
                        channels=2,
                        rate=48000,
                        output=True,
                    )
                    self.__mainDebug.info("[音频流获取器] 获取数据中...")
                    while not self.__AudioPauseStatus.is_set():
                        if self.__CloseStatus.is_set():
                            break
                        else:
                            rawData = await audioStream.stdout.readexactly(1024)
                            stream.write(rawData)
                    self.__mainDebug.debug("[音频流获取器] 任务被暂停!")
                    audioStream.terminate()
                    stream.close()
            except Exception as e:
                self.__mainDebug.error(
                    f"\n{traceback.format_exc()}\n----------Error----------"
                )
                self.__mainDebug.error("[音频流获取器] 该任务发生错误, 退出!")
                break
        if self.__CloseStatus.is_set():
            self.__mainDebug.warn("[音频流获取器] 出现全局错误申请, 退出该任务!")
        self.__CloseStatus.set()
        self.__mainDebug.warn("[音频流获取器] 任务被中止!")

    def run(self) -> None:
        self.__mainDebug.info("进程启动中...")

        async def main():
            await asyncio.gather(self.__getAudioTask())

        asyncio.run(main())

        self.__mainDebug.debug("进程已结束!")

    def play(self):
        self.__AudioPauseStatus.clear()

    def pause(self):
        self.__AudioPauseStatus.set()

    def stop(self):
        self.__CloseStatus.set()


class SubVideoProcess(Process):

    def __init__(self, logging=True, daemon=True):
        super(SubVideoProcess, self).__init__(daemon=daemon)
        if logging:
            self.__mainDebugQueue = Queue(10)
        else:
            self.__mainDebugQueue = None
        self.__mainDebug = Debug(self.__mainDebugQueue, True, "上位机-客户端模块-子视频流进程")
        self.__SubVideoPauseStatus = Event()
        self.__CloseStatus = Event()
        self.SUB_VIDEO_STATUS = mps.Value(c_bool, False)
        self.SUB_VIDEO_DATA = mps.Array(c_char, size_or_initializer=480 * 640 * 3)

    async def __getSubVideoTask(self):
        self.__mainDebug.info("[子视频流获取器] 已进入该任务")
        self.__SubVideoPauseStatus.set()
        self.SUB_VIDEO_STATUS.value = False
        while not self.__CloseStatus.is_set():
            try:
                self.__mainDebug.info("[子视频流获取器] 等待任务启动")
                while self.__SubVideoPauseStatus.is_set():
                    if self.__CloseStatus.is_set():
                        break
                    await asyncio.sleep(0)
                if self.__CloseStatus.is_set():
                    break
                else:
                    self.__mainDebug.info("[子视频流获取器] 任务启动成功!")
                    videoStream = await asyncio.subprocess.create_subprocess_shell(
                        "ffmpeg -f flv -i rtmp://139.155.181.21/live/02 -f rawvideo -pix_fmt bgr24 -",
                        stdout=asyncio.subprocess.PIPE,
                        stderr=asyncio.subprocess.DEVNULL,
                        shell=True
                    )
                    self.__mainDebug.info("[子视频流获取器] 获取数据中...")
                    while not self.__SubVideoPauseStatus.is_set():
                        if self.__CloseStatus.is_set():
                            break
                        else:
                            rawData = await videoStream.stdout.readexactly(480 * 640 * 3)
                            self.SUB_VIDEO_STATUS.value = True
                            self.SUB_VIDEO_DATA.raw = rawData
                    self.__mainDebug.debug("[子视频流获取器] 任务被暂停!")
                    videoStream.terminate()
            except Exception as e:
                self.__mainDebug.error(
                    f"\n{traceback.format_exc()}\n----------Error----------"
                )
                self.__mainDebug.error("[子视频流获取器] 该任务发生错误, 退出!")
                break
        if self.__CloseStatus.is_set():
            self.__mainDebug.warn("[子视频流获取器] 出现全局错误申请, 退出该任务!")
        self.__CloseStatus.set()
        self.__mainDebug.warn("[子视频流获取器] 任务被中止!")

    def run(self) -> None:
        self.__mainDebug.info("进程启动中...")

        async def main():
            await asyncio.gather(self.__getSubVideoTask())

        asyncio.run(main())

        self.__mainDebug.debug("进程已结束!")

    def play(self):
        self.__SubVideoPauseStatus.clear()

    def pause(self):
        self.__SubVideoPauseStatus.set()

    def stop(self):
        self.__CloseStatus.set()


class TranceProcess(Process):

    def __init__(self, sentAddr: tuple, logging=True, daemon=True):
        super(TranceProcess, self).__init__(daemon=daemon)
        if logging:
            self.__mainDebugQueue = Queue(10)
        else:
            self.__mainDebugQueue = None
        self.__mainDebug = Debug(self.__mainDebugQueue, True, "上位机-客户端模块-通信进程")
        self.__sentAddr = sentAddr
        self.commandQueue = Queue(20)
        self.__CloseStatus = Event()
        self.__TrancePauseStatus = Event()
        self.STATUS_DATA = mps.Value(StatusData, 1.0, 0.0, 0.0, 0)
        self.HEART_BEAT_DATA = mps.Value(HeartBeatData, -1, 0.0, 0.0)

    async def __messageRecv(self, client: socket.socket, saveBuffer: asyncio.Queue):
        self.__mainDebug.info("[消息接收器] 已进入该任务")
        while not self.__TrancePauseStatus.is_set():
            try:
                rlist, _, _ = select.select([client], [], [], 0)
                if len(rlist) == 0:
                    await asyncio.sleep(0)
                else:
                    data = client.recv(1024)
                    if data == b'':
                        await asyncio.sleep(0)
                    else:
                        # self.__mainDebug.debug(f"[消息接收器] 接收到的数据为:{data}")
                        await saveBuffer.put(data)
            except ConnectionError:
                self.__mainDebug.warn(f"[消息接收器] 已连接服务器，但服务器未上线!")
                await asyncio.sleep(3)
            except Exception as e:
                self.__mainDebug.error(
                    f"\n{traceback.format_exc()}\n----------Error----------"
                )
                self.__mainDebug.error("[消息接收器] 该任务发生错误, 退出!")
                break
        if self.__TrancePauseStatus.is_set():
            self.__mainDebug.warn("[消息接收器] 出现全局错误, 退出该任务!")
        self.__TrancePauseStatus.set()
        self.__mainDebug.warn("[消息接收器] 任务被中止!")

    async def __messageFresh(self, saveBuffer: asyncio.Queue):
        self.__mainDebug.info("[消息刷新器] 已进入该任务")
        statusPack = struct.Struct('< B f f f B')
        heartBeatPack = struct.Struct('< B d f f')
        while not self.__TrancePauseStatus.is_set():
            try:
                if not saveBuffer.empty():
                    rawData = await saveBuffer.get()
                    # print(len(rawData))
                    if rawData[0] == 1 and len(rawData) == 14:
                        data = statusPack.unpack(rawData)
                        self.STATUS_DATA.bat = data[1]
                        self.STATUS_DATA.t_speed = data[2]
                        self.STATUS_DATA.g_speed = data[3]
                        self.STATUS_DATA.signal = data[4]
                        await asyncio.sleep(0)
                    elif rawData[0] == 2 and len(rawData) == 17:
                        data = heartBeatPack.unpack(rawData)
                        self.HEART_BEAT_DATA.delay = (time.time() - data[1]) * 1000
                        self.HEART_BEAT_DATA.up = data[2]
                        self.HEART_BEAT_DATA.down = data[3]
                        print(self.HEART_BEAT_DATA.delay)
                        await asyncio.sleep(0)
                    else:
                        await asyncio.sleep(0)
                else:
                    await asyncio.sleep(0)
            except Exception as e:
                self.__mainDebug.error(
                    f"\n{traceback.format_exc()}\n----------Error----------"
                )
                self.__mainDebug.error("[消息刷新器] 该任务发生错误, 退出!")
                break
        if self.__TrancePauseStatus.is_set():
            self.__mainDebug.warn("[消息刷新器] 出现全局错误, 退出该任务!")
        self.__TrancePauseStatus.set()
        self.__mainDebug.warn("[消息刷新器] 任务被中止!")

    async def __messageGet(self, saveBuffer: asyncio.Queue):
        self.__mainDebug.info("[命令获取器] 已进入该任务")
        while not self.__TrancePauseStatus.is_set():
            try:
                if not self.commandQueue.empty():
                    data = self.commandQueue.get()
                    await saveBuffer.put(data)
                else:
                    await asyncio.sleep(0)
            except Exception as e:
                self.__mainDebug.error(
                    f"\n{traceback.format_exc()}\n----------Error----------"
                )
                self.__mainDebug.error("[命令获取器] 该任务发生错误, 退出!")
                break
        if self.__TrancePauseStatus.is_set():
            self.__mainDebug.warn("[命令获取器] 出现全局错误, 退出该任务!")
        self.__TrancePauseStatus.set()
        self.__mainDebug.warn("[命令获取器] 任务被中止!")

    async def __messageSent(self, client: socket.socket, saveBuffer: asyncio.Queue):
        self.__mainDebug.info("[命令发送器] 已进入该任务")
        while not self.__TrancePauseStatus.is_set():
            try:
                if not saveBuffer.empty():
                    data = await saveBuffer.get()
                    self.__mainDebug.debug(f"[命令发送器] 数据已发送...")
                    client.send(data)
                else:
                    await asyncio.sleep(0)
            except ConnectionAbortedError:
                self.__mainDebug.warn("[命令发送器] 已连接服务器, 但服务器未上线")
                await asyncio.sleep(3)
            except Exception as e:
                self.__mainDebug.error(
                    f"\n{traceback.format_exc()}\n----------Error----------"
                )
                self.__mainDebug.error("[命令发送器] 该任务发生错误, 退出!")
                break
        if self.__TrancePauseStatus.is_set():
            self.__mainDebug.warn("[命令发送器] 出现全局错误, 退出该任务!")
        self.__TrancePauseStatus.set()
        self.__mainDebug.warn("[命令发送器] 任务被中止!")

    def run(self) -> None:
        self.__mainDebug.info("进程启动中...")
        sentAddr = self.__sentAddr
        self.__TrancePauseStatus.set()
        while not self.__CloseStatus.is_set():
            try:
                self.__mainDebug.info("等待连接服务器")
                while self.__TrancePauseStatus.is_set():
                    if self.__CloseStatus.is_set():
                        break
                    time.sleep(0.1)
                if self.__CloseStatus.is_set():
                    break
                else:
                    self.__mainDebug.info("准备连接服务器中...")
                    client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
                    self.__mainDebug.info("服务器连接中...")
                    client.connect(sentAddr)
                    self.__mainDebug.info("服务器连接成功，验证服务器中")
                    nums = 0
                    while nums < 3:
                        rlist, _, _ = select.select([client], [], [], 0)
                        if len(rlist) == 0:
                            time.sleep(1)
                            nums += 1
                            self.__mainDebug.warn(f"服务器无反应! 已拨号->{nums}次")
                        else:
                            data = client.recv(1024)
                            if data == b'Hello':
                                self.__mainDebug.debug("服务器验证成功")
                                break
                            else:
                                nums += 1
                                self.__mainDebug.warn(f"服务器验证失败! 已拨号->{nums}次")
                    if nums >= 3:
                        self.__mainDebug.error("服务器连接失败, 重新连接!")
                        client.close()
                        self.__TrancePauseStatus.set()
                        continue
                    loop = asyncio.new_event_loop()

                    recvQueue = asyncio.Queue(20, loop=loop)
                    sentQueue = asyncio.Queue(20, loop=loop)

                    async def main():
                        messageRecv = loop.create_task(self.__messageRecv(client, recvQueue))
                        messageGet = loop.create_task(self.__messageGet(sentQueue))
                        messageSent = loop.create_task(self.__messageSent(client, sentQueue))
                        messageFresh = loop.create_task(self.__messageFresh(recvQueue))
                        await asyncio.gather(messageRecv, messageGet, messageSent, messageFresh)

                    loop.run_until_complete(main())
                    client.close()
                    self.__mainDebug.info("全任务结束, 重新进入等待")
            except Exception as e:
                self.__mainDebug.error(
                    f"\n{traceback.format_exc()}\n----------Error----------"
                )
                self.__mainDebug.error("连接服务器时发生错误，退出!")
                break
        if self.__CloseStatus.is_set():
            self.__mainDebug.warn("出现全局错误申请, 退出该进程!")
        self.__CloseStatus.set()
        self.__mainDebug.debug("进程中止!")

    def play(self):
        self.__TrancePauseStatus.clear()

    def pause(self):
        self.__TrancePauseStatus.set()

    def stop(self):
        self.__CloseStatus.set()

    def isConnected(self):
        return not self.__TrancePauseStatus.is_set()


class WindowInit(QMainWindow):

    def __init__(self):
        super(WindowInit, self).__init__()
        # 获取屏幕桌面对象
        self.__desktop = QApplication.desktop()
        self.__screeRect = self.__desktop.screenGeometry()
        # 获取屏幕高度和屏幕宽度
        self.screenheight = self.__screeRect.height()
        self.screenwidth = self.__screeRect.width()
        # 获取界面初始化高度和宽度
        self.guiHig = int(self.screenheight / 2)
        self.guiWid = int(self.screenwidth / 2)
        # 界面大小初始化
        self.setGeometry(0, 0, self.guiWid, self.guiHig)
        self.sentMediaProcess: Optional[subprocess.Popen] = None
        self.controlPack = struct.Struct('< B ? ? ? ? f')
        self.heartBeatPack = struct.Struct('< B d ?')

        self.pointPixmap = QPixmap("icon/point.webp")
        self.mainProcess = MainVideoProcess()
        self.audioProcess = AudioProcess()
        self.subProcess = SubVideoProcess()
        self.tranceProcess = TranceProcess(('139.155.181.21', 8500))
        self.tranceProcess.start()

        self.MAIN_VIDEO_STATUS = self.mainProcess.MAIN_VIDEO_STATUS
        self.MAIN_VIDEO_DATA = self.mainProcess.MAIN_VIDEO_DATA

        self.SUB_VIDEO_STATUS = self.subProcess.SUB_VIDEO_STATUS
        self.SUB_VIDEO_DATA = self.subProcess.SUB_VIDEO_DATA

        self.COMMAND_QUEUE = self.tranceProcess.commandQueue
        self.STATUS_DATA = self.tranceProcess.STATUS_DATA
        self.HEART_BEAT_DATA = self.tranceProcess.HEART_BEAT_DATA

        self.mainProcess.start()
        self.subProcess.start()
        self.audioProcess.start()

        self.freshImageTimer = QTimer()
        self.freshImageTimer.setInterval(33)
        self.freshImageTimer.timeout.connect(self.__freshMainImage)
        self.freshImageTimer.start()

        self.freshHeartBeatTimer = QTimer()
        self.freshHeartBeatTimer.setInterval(300)
        self.freshHeartBeatTimer.timeout.connect(self.__freshHeartBeat)
        self.freshHeartBeatTimer.start()

        self.freshGlobalDataTimer = QTimer()
        self.freshGlobalDataTimer.setInterval(30)
        self.freshGlobalDataTimer.timeout.connect(self.__freshGlobalData)
        self.freshGlobalDataTimer.start()

        self.TRANCE_PAUSE = False
        self.MEDIA_RECV = False
        self.MEDIA_SENT = False
        self.KEY_ALT = False

        self.SENT_CAMERA = "ffmpeg -f dshow -r 30 -s 1280x720 -i video=\"Integrated Camera\" -f dshow -i audio=\"麦克风阵列 (Synaptics SmartAudio HD)\" -ac 2 -ar 48000 -b:v 1000k -b:a 500k -sc_threshold 499 -vprofile main -preset ultrafast -tune zerolatency -vcodec h264_amf -f flv rtmp://139.155.181.21/live/03"

        self.controlDict = {
            'up': False,
            'down': False,
            'left': False,
            'right': False,
            'speed': 0,
        }
        self.copyControlDict = self.controlDict.copy()
        # 加载中心布局
        self.__loadCenter()
        self.setMouseTracking(True)
        self.grabMouse()
        self.setCursor(Qt.BlankCursor)

    def __loadCenter(self):
        # 创建中央控件
        self.centerFrame = QLabel()
        self.centerFrame.setPixmap(self.pointPixmap)
        self.centerFrame.setScaledContents(True)
        self.centerFrame.setAutoFillBackground(True)
        # 配置中央控件
        self.centerFrame.setFrameShape(QFrame.Box)
        self.centerFrame.setFrameShadow(QFrame.Plain)
        self.centerFrame.setLineWidth(3)
        self.centerFrame.setMinimumSize(self.guiWid, self.guiHig)
        # 完善中央控件
        # - 各种模组
        self.batWid = BatWid(self.centerFrame.width(), self.centerFrame.height(), self.centerFrame)
        self.batWid.setValue(80)
        self.sigWid = SignalWid(1758, 31, self.centerFrame.width(), self.centerFrame.height(),
                                parent=self.centerFrame)
        self.sigWid.setValue(3)
        self.backWid = BackMirror(630, 0, self.centerFrame.width(), self.centerFrame.height(),
                                  parent=self.centerFrame)
        self.backWid.setValue('20', 11.41, 12.42)
        self.backVideoWid = BackMirrorVideo(600, 172, self.centerFrame.width(), self.centerFrame.height(),
                                            parent=self.centerFrame)
        self.speedWid = SpeedPan(29, 829, self.centerFrame.width(), self.centerFrame.height(),
                                 parent=self.centerFrame)
        self.speedWid.setValue(23.5)
        # self.videoWid = VideoBox(1550, 200, self.centerFrame.width(), self.centerFrame.height(),
        #                          parent=self.centerFrame)
        self.mapWid = MapBox(1380, 770, self.centerFrame.width(), self.centerFrame.height(),
                             parent=self.centerFrame)
        self.helperWid = Helper(50, 200, self.centerFrame.width(), self.centerFrame.height(),
                                parent=self.centerFrame)
        self.camSelect = CamWindow(parent=self)
        # 加载中央控件
        self.setCentralWidget(self.centerFrame)
        self.grabKeyboard()

    def keyPressEvent(self, e: QKeyEvent) -> None:
        key = e.key()
        keyStatus = e.isAutoRepeat()
        if not keyStatus:
            if key == Qt.Key_W:
                self.controlDict['up'] = True
                print("前进")
            elif key == Qt.Key_S:
                self.controlDict['down'] = True
                print("后退")
            elif key == Qt.Key_A:
                self.controlDict['left'] = True
                print("左转")
            elif key == Qt.Key_D:
                self.controlDict['right'] = True
                print("右转")
            elif key == Qt.Key_Alt:
                self.KEY_ALT = not self.KEY_ALT
                self.setMouseTracking(self.KEY_ALT)
                if not self.KEY_ALT:
                    self.releaseMouse()
                    self.unsetCursor()
                else:
                    self.grabMouse()
                    self.setCursor(Qt.BlankCursor)
                print("释放鼠标")
            elif key == Qt.Key_H:
                self.helperWid.setHidden(False)
                print("开关帮助手册")
            elif key == Qt.Key_Tab:
                self.backVideoWid.setHidden(False)
                print("开关副窗口")
            elif key == Qt.Key_F:
                print("开关图传画面")
                self.helperWid.setHidden(True)
                self.MEDIA_RECV = not self.MEDIA_RECV
                if self.MEDIA_RECV:
                    self.mainProcess.play()
                    self.audioProcess.play()
                    self.subProcess.play()
                    self.freshImageTimer.start()
                else:
                    self.mainProcess.pause()
                    self.audioProcess.pause()
                    self.subProcess.pause()
                    self.freshImageTimer.stop()
            elif key == Qt.Key_B:
                print("开关设置窗口")
                if self.MEDIA_SENT:
                    self.sentMediaProcess.terminate()
                self.setMouseTracking(False)
                self.KEY_ALT = False
                self.setMouseTracking(False)
                self.releaseMouse()
                self.unsetCursor()
                self.camSelect.freshCamList()
                self.camSelect.show()

            elif key == Qt.Key_V:
                self.MEDIA_SENT = not self.MEDIA_SENT
                if self.MEDIA_SENT:
                    self.sentMediaProcess = subprocess.Popen(
                        self.SENT_CAMERA,
                        stdout=subprocess.DEVNULL)
                    print("已开启发送流")
                    self.TRANCE_PAUSE = True
                else:
                    self.sentMediaProcess.terminate()
                    self.TRANCE_PAUSE = False
                    print("已关闭发送流")
            elif key == Qt.Key_R:
                # self.tranceProcess.play()
                if self.tranceProcess.isConnected():
                    self.tranceProcess.pause()
                else:
                    self.tranceProcess.play()
                    # self.backWid.setValue('-1', up=0, down=0)
                    # self.batWid.setValue(0)
                    # self.speedWid.setValue(0)
                    # self.sigWid.setValue(0)
            elif key == Qt.Key_Escape:
                self.close()
            elif key == Qt.Key_I:
                if self.controlDict['speed'] < 100:
                    self.controlDict['speed'] += 20
                print("速度增加")
            elif key == Qt.Key_O:
                print("速度减小")
                if self.controlDict['speed'] > 0:
                    self.controlDict['speed'] -= 20
            print(self.controlDict)
            # print(self.copyControlDict)
            if self.controlDict != self.copyControlDict:
                # print("进入发送")
                sentData = (
                    1,
                    self.controlDict['up'],
                    self.controlDict['down'],
                    self.controlDict['left'],
                    self.controlDict['right'],
                    self.controlDict['speed']
                )
                # print("结构组建完毕")
                self.COMMAND_QUEUE.put(self.controlPack.pack(*sentData))
                # print("发送完毕")
                self.copyControlDict = self.controlDict.copy()
                # print(sentData)
            # print('发送完毕')
        # 以上是基础的小车控制

    def keyReleaseEvent(self, e: QKeyEvent) -> None:
        key = e.key()
        keyStatus = e.isAutoRepeat()
        if not keyStatus:
            if key == Qt.Key_W:
                self.controlDict['up'] = False
            elif key == Qt.Key_S:
                self.controlDict['down'] = False
            elif key == Qt.Key_A:
                self.controlDict['left'] = False
            elif key == Qt.Key_D:
                self.controlDict['right'] = False
            # 以上是基础的小车控制
            elif key == Qt.Key_H:
                self.helperWid.setHidden(True)
                print("释放帮助手册")
            elif key == Qt.Key_Tab:
                self.backVideoWid.setHidden(True)
                print("释放副窗口")
            if self.controlDict != self.copyControlDict:
                sentData = (
                    1,
                    self.controlDict['up'],
                    self.controlDict['down'],
                    self.controlDict['left'],
                    self.controlDict['right'],
                    self.controlDict['speed']
                )
                self.COMMAND_QUEUE.put(self.controlPack.pack(*sentData))
                self.copyControlDict = self.controlDict.copy()

    def resizeEvent(self, event: QResizeEvent) -> None:
        try:
            self.batWid.updSize(self.centerFrame.width(), self.centerFrame.height())
            self.sigWid.updSize(self.centerFrame.width(), self.centerFrame.height())
            self.backWid.updSize(self.centerFrame.width(), self.centerFrame.height())
            self.speedWid.updSize(self.centerFrame.width(), self.centerFrame.height())
            # self.videoWid.updSize(self.centerFrame.width(), self.centerFrame.height())
            self.mapWid.updSize(self.centerFrame.width(), self.centerFrame.height())
            self.helperWid.updSize(self.centerFrame.width(), self.centerFrame.height())
            self.backVideoWid.updSize(self.centerFrame.width(), self.centerFrame.height())
        except Exception as e:
            repr(e)

    def changeEvent(self, a0: QEvent) -> None:
        try:
            self.batWid.updSize(self.centerFrame.width(), self.centerFrame.height())
            self.sigWid.updSize(self.centerFrame.width(), self.centerFrame.height())
            self.backWid.updSize(self.centerFrame.width(), self.centerFrame.height())
            self.speedWid.updSize(self.centerFrame.width(), self.centerFrame.height())
            # self.videoWid.updSize(self.centerFrame.width(), self.centerFrame.height())
            self.mapWid.updSize(self.centerFrame.width(), self.centerFrame.height())
            self.helperWid.updSize(self.centerFrame.width(), self.centerFrame.height())
            self.backVideoWid.updSize(self.centerFrame.width(), self.centerFrame.height())
        except Exception as e:
            repr(e)

    def __freshMainImage(self):
        if self.MEDIA_RECV:
            if self.MAIN_VIDEO_STATUS.value:
                payload = self.MAIN_VIDEO_DATA.raw
                frame = np.frombuffer(payload, np.uint8).reshape((480, 640, 3))
                imageCV2_RGB = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
                # print("成功读取2")
                imageRow, imageCol, imageChannel = imageCV2_RGB.shape
                # print("成功读取3")
                byterPerLine = imageCol * imageChannel
                # print("成功读取4")
                imageQt = QImage(imageCV2_RGB, imageCol, imageRow, byterPerLine, QImage.Format_RGB888)
                # print("成功读取5")
                imageQPixmap = QPixmap.fromImage(imageQt)
                # print("成功读取6")
                self.centerFrame.setPixmap(imageQPixmap)
            else:
                self.centerFrame.setPixmap(self.pointPixmap)
            # print(self.SUB_VIDEO_STATUS.value)
            if self.SUB_VIDEO_STATUS.value:
                payload = self.SUB_VIDEO_DATA.raw
                frame = np.frombuffer(payload, np.uint8).reshape((480, 640, 3))
                imageCV2_RGB = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
                # print("成功读取2")
                imageRow, imageCol, imageChannel = imageCV2_RGB.shape
                # print("成功读取3")
                byterPerLine = imageCol * imageChannel
                # print("成功读取4")
                imageQt = QImage(imageCV2_RGB, imageCol, imageRow, byterPerLine, QImage.Format_RGB888)
                # print("成功读取5")
                imageQPixmap = QPixmap.fromImage(imageQt)
                # print("成功读取6")
                self.backVideoWid.myVideoCanvas.setPixmap(imageQPixmap)
            else:
                self.backVideoWid.myVideoCanvas.setPixmap(self.pointPixmap)
            self.freshImageTimer.start()
        else:
            self.centerFrame.setPixmap(self.pointPixmap)

    def __freshHeartBeat(self):
        if self.tranceProcess.isConnected():
            rawData = (
                2,
                time.time(),
                self.TRANCE_PAUSE,
            )
            self.COMMAND_QUEUE.put(self.heartBeatPack.pack(*rawData))
        self.freshHeartBeatTimer.start()

    def __freshGlobalData(self):
        if self.tranceProcess.isConnected():
            delay, up, down = str(int(self.HEART_BEAT_DATA.delay)), \
                              round(self.HEART_BEAT_DATA.up, 1), \
                              round(self.HEART_BEAT_DATA.down, 1)
            self.backWid.setValue(delay, up=up, down=down)
            self.batWid.setValue(round(self.STATUS_DATA.bat, 2))
            self.speedWid.setValue(round(self.STATUS_DATA.t_speed, 2))
            self.sigWid.setValue(self.STATUS_DATA.signal)
        self.freshGlobalDataTimer.start()

    def closeEvent(self, a0: QCloseEvent) -> None:
        self.controlDict['client'] = False
        self.mainProcess.stop()
        self.audioProcess.stop()
        self.subProcess.stop()
        self.tranceProcess.pause()
        self.tranceProcess.stop()
        if self.MEDIA_SENT:
            self.sentMediaProcess.terminate()
        self.mainProcess.join()
        self.audioProcess.join()
        self.subProcess.join()
        self.tranceProcess.join()

    def windowShow(self):
        self.show()

    def mouseMoveEvent(self, a0: QMouseEvent) -> None:
        # QCursor.setPos(self.frameSize())
        if self.KEY_ALT:
            QCursor.setPos(int(self.frameSize().width() / 2), int(self.frameSize().height() / 2))


if __name__ == '__main__':
    app = QApplication(sys.argv)
    main_window = WindowInit()
    main_window.windowShow()
    sys.exit(app.exec_())
    # proc = MainVideoProcess()
    # proc2 = MainAudioProcess()
    # proc.start()
    # proc2.start()
    # time.sleep(2)
    # proc.play()
    # proc2.play()
    # proc.join()
    # proc2.join()
